package edu.cmu.cs211.exprtree.ast;

/**
 * Represents an expression that has two arguments. In other words, traditional
 * binary operators (+,-,*,/).
 */
public abstract class BinaryExpression implements Expression {

	// fields
	private final Expression l;
	private final Expression r;
	
	/**
	 * Creates a new {@link BinaryExpression}
	 * 
	 * @param l
	 *            the left node of the new expression
	 * @param r
	 *            the right node of the new expression
	 * @throws NullPointerException
	 *             if l or r is <code>null</code>.
	 */
	public BinaryExpression (Expression l, Expression r) {
		if (l == null || r == null)
			throw new NullPointerException();
		this.l = l;
		this.r = r;
	}

	/** Accessor for the left node */
	public final Expression getLeft ()
	{
		return l;
	}

	/** Accessor for the right node */
	public final Expression getRight ()
	{
		return r;
	}

	/**
	 * Gets the symbol that represents this operation
	 * 
	 * @return the text symbol that represents this operator, for example '+'
	 *         for {@link AddExpression}
	 */
	public abstract char getOperatorSymbol ();

	/** Returns the string (l op r) (with no spaces). For example, (x+y) */
	@Override
	public String toString ()
	{
		String s = String.format ("(%s%s%s)", getLeft (), getOperatorSymbol (),getRight ());
		return s;
	}

	@Override
	public boolean equals (Object obj)
	{
		if (this == obj)
			return true;
		if (obj == null)
			return false;

		if (!obj.getClass ().equals (getClass ()))
			return false;
		return ((BinaryExpression) obj).getLeft ().equals (getLeft ())
		        && ((BinaryExpression) obj).getRight ().equals (getRight ());
	}

	@Override
	public int hashCode ()
	{
		int lh = getLeft ().hashCode ();
		int rh = getRight ().hashCode ();
		int ch = getClass ().hashCode ();

		return (lh << 7 | lh >>> 25) ^ (rh << 17 | rh >>> 15)
		        ^ (ch << 8 | ch >>> 24);
	}
}
